/**
 * 
 */
package com.sfeir.client.service;

import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sfeir.client.util.Constants;
import com.sfeir.shared.Level;

/**
 * @author François LAROCHE
 *
 */
public class CachedAppServiceAsync implements AppServiceAsync {

	private final AppServiceAsync delegate;
	private List<Level> levels;
	private List<Map<String, Object>> userLevels;

	public CachedAppServiceAsync() {
		this((AppServiceAsync)GWT.create(AppService.class));
	}

	public CachedAppServiceAsync(AppServiceAsync delegate) {
		this.delegate = delegate;
	}

	@Override
	public void getLevels(final AsyncCallback<List<Level>> callback) {
		if(this.levels != null) {
			callback.onSuccess(this.levels);
		}
		else {
			this.delegate.getLevels(new AsyncCallback<List<Level>>() {
				@Override
				public void onFailure(Throwable caught) {
					callback.onFailure(caught);
				}
				@Override
				public void onSuccess(List<Level> result) {
					levels = result;
					callback.onSuccess(levels);
				}
			});
		}
	}

	@Override
	public void getUserLevels(final AsyncCallback<List<Map<String, Object>>> callback) {
		if(this.userLevels != null) {
			callback.onSuccess(userLevels);
		}
		else {
			this.delegate.getUserLevels(new AsyncCallback<List<Map<String,Object>>>() {
				@Override
				public void onFailure(Throwable caught) {
					callback.onFailure(caught);
				}
				@Override
				public void onSuccess(List<Map<String, Object>> result) {
					userLevels = result;
					callback.onSuccess(userLevels);
				}
			});
		}
	}

	@Override
	public void saveScore(final int levelOrder, final int score, final AsyncCallback<Integer> callback) {
		// !!!! We Assume the list of scores is already loaded !!!!
		this.delegate.saveScore(levelOrder, score, new AsyncCallback<Integer>() {
			@Override
			public void onFailure(Throwable caught) {
				callback.onFailure(caught);
			}
			@Override
			public void onSuccess(Integer result) {
				Map<String, Object> currentScore = userLevels.get(levelOrder - 1);
				Integer oldScore = (Integer)currentScore.get(Constants.MAP_SCORE_KEY);
				if(oldScore == null || oldScore == 0 || score < oldScore) {
					currentScore.put(Constants.MAP_SCORE_KEY, score);
					currentScore.put(Constants.MAP_STARS_KEY, result);
				}
				if(result > 0 && levelOrder < userLevels.size()) {
					Map<String, Object> nextScore = userLevels.get(levelOrder);
					nextScore.put(Constants.MAP_ISUNLOCKED_KEY, 0);
				}
				callback.onSuccess(result);
			}
		});
	}

	@Override
	public void getNextToBeat(int level, final AsyncCallback<List<Map<String, Object>>> callback) {
		delegate.getNextToBeat(level, new AsyncCallback<List<Map<String,Object>>>() {
			@Override
			public void onFailure(Throwable caught) {
				callback.onFailure(caught);
			}
			@Override
			public void onSuccess(List<Map<String, Object>> result) {
				callback.onSuccess(result);
			}
		});
	}

	@Override
	public void getNickname(AsyncCallback<String> callback) {
		this.delegate.getNickname(callback);
	}

	@Override
	public void getLogoutUrl(AsyncCallback<String> callback) {
		this.delegate.getLogoutUrl(callback);
	}

}
